package com.jt1078.streamserver;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class JT1078TestPusher {
    public static void main(String[] args) throws Exception {
//        String sim = "13912345678"; // 12位BCD
        String sim = "13912345678"; // 12位BCD
        int channelNo = 1; // 1号通道
        String host = "127.0.0.1";
        int port = 6078;
        File h264File = new File("G:\\out.h264");

        List<byte[]> naluList = splitH264File(h264File);

        // 打印每个NALU类型
        for (byte[] nalu : naluList) {
            int offset = (nalu[2] == 1) ? 3 : 4;
            int naluType = nalu.length > offset ? (nalu[offset] & 0x1F) : -1;
            System.out.printf("NALU len=%d, type=%d, head=%02x %02x %02x %02x %02x\n",
                    nalu.length, naluType, nalu[0], nalu[1], nalu[2], nalu[3], nalu.length > offset ? nalu[offset] : 0);
        }

        Socket socket = new Socket(host, port);
        OutputStream out = socket.getOutputStream();

        int seq = 0;
        for (byte[] nalu : naluList) {
            byte[] packet = buildJT1078Packet(sim, channelNo, nalu, seq++);
            out.write(packet);
            out.flush();
            Thread.sleep(40); // 25fps
        }
        out.close();
        socket.close();
        System.out.println("推流完成");
    }

    // 支持3字节、4字节起始码的NALU分割
    public static List<byte[]> splitH264File(File file) throws IOException {
        byte[] data = new byte[(int) file.length()];
        FileInputStream fis = new FileInputStream(file);
        fis.read(data);
        fis.close();

        List<byte[]> list = new ArrayList<>();
        int start = findStartCode(data, 0);
        while (start != -1) {
            int next = findStartCode(data, start + 3);
            if (next != -1) {
                byte[] nalu = new byte[next - start];
                System.arraycopy(data, start, nalu, 0, nalu.length);
                list.add(nalu);
                start = next;
            } else {
                // 最后一个NALU
                byte[] nalu = new byte[data.length - start];
                System.arraycopy(data, start, nalu, 0, nalu.length);
                list.add(nalu);
                break;
            }
        }
        return list;
    }

    // 检测下一个起始码（支持3字节/4字节）
    private static int findStartCode(byte[] data, int offset) {
        for (int i = offset; i < data.length - 3; i++) {
            if (data[i] == 0 && data[i + 1] == 0) {
                if (data[i + 2] == 1) return i;          // 00 00 01
                if (data[i + 2] == 0 && data[i + 3] == 1) return i; // 00 00 00 01
            }
        }
        return -1;
    }

    // 构造JT1078包（NALU含起始码）
    public static byte[] buildJT1078Packet(String sim, int channel, byte[] nalu, int seq) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            baos.write(new byte[] {0x30, 0x31, 0x63, 0x64});
            baos.write(bcd(sim, 6));
            baos.write(channel & 0xFF);
            baos.write(0); // 数据类型，简单设为0
            baos.write(new byte[] {0x00, 0x19}); // 帧率25
            int ts = seq * 40;
            baos.write((ts >> 24) & 0xFF);
            baos.write((ts >> 16) & 0xFF);
            baos.write((ts >> 8) & 0xFF);
            baos.write(ts & 0xFF);
            baos.write((seq >> 8) & 0xFF);
            baos.write(seq & 0xFF);
            baos.write(0x00); // 分包标志
            baos.write(nalu);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return baos.toByteArray();
    }

    // SIM号转BCD
    public static byte[] bcd(String sim, int len) {
        String s = String.format("%" + (len * 2) + "s", sim).replace(' ', '0');
        byte[] out = new byte[len];
        for (int i = 0; i < out.length; i++) {
            int high = charToHex(s.charAt(i * 2));
            int low = charToHex(s.charAt(i * 2 + 1));
            out[i] = (byte)((high << 4) | low);
        }
        return out;
    }
    private static int charToHex(char c) {
        return c >= '0' && c <= '9' ? (c - '0') : 0;
    }
}
